home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene 96
/
Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso
/
misc
/
coding
/
cp2dekit
/
samples
/
loadxm.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-29
|
21KB
|
827 lines
//***************************************************************************
//
// this file is (c) '94-'96 Niklas Beisert
//
// this file is part of the cubic player development kit.
// you may only use/modify/spread this file under the terms stated
// in the cubic player development kit accompanying documentation.
//
//***************************************************************************
//[filetype 10]
// color=3
// name=XM
// interface=_plCubicPlayer
// player=_gmdPlayer
// ldlink=loadxm
// loader=mpLoadXM_
// loader example
#include <string.h>
#include "binfile.h"
#include "mcp.h"
#include "mp.h"
#include "err.h"
static inline void putcmd(unsigned char *&p, unsigned char c, unsigned char d)
{
*p++=c;
*p++=d;
}
static inline void advancenote(unsigned char *&x)
{
unsigned char s=*x;
if (s&0x80)
{
x++;
if (s&1)
x++;
if (s&2)
x++;
if (s&4)
x++;
if (s&8)
x++;
if (s&16)
x++;
}
else
x+=5;
}
extern "C" int mpLoadXM(module &m, binfile &file)
{
m.reset();
struct
{
char sig[17];
char name[20];
char whythis1a;
char tracker[20];
unsigned short ver;
unsigned long hdrsize;
} head1;
struct
{
unsigned short ordnum;
unsigned short restart;
unsigned short channum;
unsigned short patnum;
unsigned short insnum;
unsigned short freqtab;
unsigned short tempo;
unsigned short speed;
unsigned char ord[256];
} head2;
file.read(&head1, sizeof(head1));
if (memcmp(head1.sig, "Extended Module: ", 17))
return errFormSig;
if (head1.whythis1a!=26)
return errFormStruc;
if (head1.ver<0x104)
return errFormOldVer;
file.read(&head2, sizeof(head2));
file.seekcur(head1.hdrsize-4-sizeof(head2));
if (!head2.insnum)
return errFormMiss;
memcpy(m.name, head1.name, 20);
m.name[20]=0;
m.options=(head2.freqtab&1)?MOD_EXPOFREQ:0;
m.channum=head2.channum;
m.instnum=head2.insnum;
m.envnum=head2.insnum*2;
m.patnum=head2.patnum+1;
m.ordnum=head2.ordnum;
m.endord=m.ordnum;
m.tracknum=(head2.channum+1)*head2.patnum+1;
m.loopord=head2.restart;
sampleinfo **smps=new sampleinfo *[m.instnum];
sample **msmps=new sample *[m.instnum];
int *instsmpnum=new int [m.instnum];
if (!instsmpnum||!m.allocinstruments()||!m.allocpatterns()||!m.alloctracks()||!m.allocenvelopes()||!smps||!msmps||!m.allocorders())
return errAllocMem;
int i,t,j;
for (i=0; i<m.ordnum; i++)
m.orders[i]=(head2.ord[i]<head2.patnum)?head2.ord[i]:head2.patnum;
for (i=0; i<m.channum; i++)
m.patterns[head2.patnum].tracks[i]=m.tracknum-1;
m.patterns[head2.patnum].gtrack=m.tracknum-1;
m.patterns[head2.patnum].patlen=64;
unsigned char *temptrack=new unsigned char[3000];
unsigned short buflen=2048;
unsigned char *buffer=new unsigned char[buflen];
if (!buffer||!temptrack)
return errAllocMem;
for (t=0; t<head2.patnum; t++)
{
struct
{
unsigned long len;
unsigned char ptype;
unsigned short rows;
unsigned short patdata;
} pathead;
file.read(&pathead, sizeof(pathead));
file.seekcur(pathead.len-sizeof(pathead));
pattern &pp=m.patterns[t];
for (i=0; i<m.channum; i++)
pp.tracks[i]=t*(m.channum+1)+i;
pp.gtrack=t*(m.channum+1)+m.channum;
pp.patlen=pathead.rows;
int clean=0;
if (pathead.patdata==0)
{
clean=1;
pathead.patdata=m.channum*pathead.rows;
}
if (pathead.patdata>buflen)
{
buflen=pathead.patdata;
delete buffer;
buffer=new unsigned char[buflen];
if (!buffer)
return errAllocMem;
}
if (clean)
memset(buffer, 0x80, pathead.patdata);
else
file.read(buffer, pathead.patdata);
for (i=0; i<m.channum; i++)
{
unsigned char *tp=temptrack;
unsigned char *buf=buffer;
char xxq;
for (xxq=0; xxq<i; xxq++)
advancenote(buf);
unsigned short row;
for (row=0; row<pathead.rows; row++)
{
unsigned char *cp=tp+2;
signed short nte=-1;
unsigned char vol=0;
signed short pan=-1;
signed short volv=-1;
signed short ins=-1;
unsigned char command=0;
unsigned char data=0;
unsigned char x=0x1F;
if (*buf&0x80)
x=*buf++&~0x80;
if (x&1)
{
nte=11+(*buf++&~0x80);
if (nte==11) // ???
nte=-1;
}
if (x&2)
ins=*buf++-1;
if (x&4)
vol=*buf++;
if (x&8)
command=*buf++;
if (x&16)
data=*buf++;
if (row!=(pathead.rows-1))
for (xxq=0; xxq<(m.channum-1); xxq++)
advancenote(buf);
if ((vol>=0x10)&&(vol<=0x50))
volv=vol-0x10;
if (command==0xC)
volv=data;
if ((vol&0xF0)==0xC0)
pan=(vol&0xF)+((vol&0xF)<<4);
if (command==0x8)
pan=data;
if ((command==0xE)&&((data&0xF0)==0x80))
pan=(data&0xF)+((data&0xF)<<4);
if (((command==0x3)||(command==0x5)||((vol&0xF0)==0xF0))&&(nte!=-1)&&(nte!=108))
nte|=128;
if ((ins!=-1)||(nte!=-1)||(volv!=-1)||(pan!=-1))
{
if (nte==108)
{
putcmd(cp, cmdKeyOff, 0);
nte=-1;
}
unsigned char &act=*cp;
*cp++=cmdPlayNote;
if (ins!=-1)
{
act|=cmdPlayIns;
*cp++=ins;
}
if (nte!=-1)
{
act|=cmdPlayNte;
*cp++=nte;
}
if (volv!=-1)
{
act|=cmdPlayVol;
*cp++=(volv==0x40)?0xFF:(volv<<2);
}
if (pan!=-1)
{
act|=cmdPlayPan;
*cp++=pan;
}
if ((command==0xE)&&((data>>4)==0xD))
{
act|=cmdPlayDelay;
*cp++=data&0xF;
}
}
if ((vol&0xF0)==0x60)
if (vol&0xF)
putcmd(cp, cmdVolSlideDown, (vol&0x0F)<<2);
if ((vol&0xF0)==0x70)
if (vol&0xF)
putcmd(cp, cmdVolSlideUp, (vol&0x0F)<<2);
if ((vol&0xF0)==0x80)
if (vol&0xF)
putcmd(cp, cmdRowVolSlideDown, (vol&0x0F)<<2);
if ((vol&0xF0)==0x90)
if (vol&0xF)
putcmd(cp, cmdRowVolSlideUp, (vol&0x0F)<<2);
if ((vol&0xF0)==0xA0)
putcmd(cp, cmdPitchVibratoSetSpeed, vol&0x0F);
if ((vol&0xF0)==0xB0)
putcmd(cp, cmdPitchVibrato, (vol&0x0F)<<4);
if ((vol&0xF0)==0xD0)
if (vol&0xF)
putcmd(cp, cmdPanSlide, -(vol&0x0F));
if ((vol&0xF0)==0xE0)
if (vol&0xF)
putcmd(cp, cmdPanSlide, vol&0x0F);
if ((vol&0xFFF0)==0xF0)
putcmd(cp, cmdPitchSlideToNote, (vol&0x0F)<<4);
switch (command)
{
case 0x0:
if (data)
putcmd(cp, cmdArpeggio, data);
break;
case 0x1:
putcmd(cp, cmdPitchSlideUp, data);
break;
case 0x2:
putcmd(cp, cmdPitchSlideDown, data);
break;
case 0x3:
putcmd(cp, cmdPitchSlideToNote, data);
break;
case 0x4:
putcmd(cp, cmdPitchVibrato, data);
break;
case 0x5:
putcmd(cp, cmdPitchSlideToNote, 0);
if (!data)
putcmd(cp, cmdSpecial, cmdContVolSlide);
else
if (data&0xF0)
putcmd(cp, cmdVolSlideUp, (data>>4)<<2);
else
putcmd(cp, cmdVolSlideDown, (data&0xF)<<2);
break;
case 0x6:
putcmd(cp, cmdPitchVibrato, 0);
if (!data)
putcmd(cp, cmdSpecial, cmdContVolSlide);
else
if (data&0xF0)
putcmd(cp, cmdVolSlideUp, (data>>4)<<2);
else
putcmd(cp, cmdVolSlideDown, (data&0xF)<<2);
break;
case 0x7:
putcmd(cp, cmdVolVibrato, data);
break;
case 0x9:
if (nte!=-1)
putcmd(cp, cmdOffset, data);
break;
case 0xA:
if (!data)
putcmd(cp, cmdSpecial, cmdContVolSlide);
else
if (data&0xF0)
putcmd(cp, cmdVolSlideUp, (data>>4)<<2);
else
putcmd(cp, cmdVolSlideDown, (data&0xF)<<2);
break;
case 0xE:
command=data>>4;
data&=0xF;
switch (command)
{
case 0x1:
putcmd(cp, cmdRowPitchSlideUp, data<<4);
break;
case 0x2:
putcmd(cp, cmdRowPitchSlideDown, data<<4);
break;
case 0x3:
putcmd(cp, cmdSpecial, data?cmdGlissOn:cmdGlissOff);
break;
case 0x4:
if (data<4)
putcmd(cp, cmdPitchVibratoSetWave, data);
break;
case 0x7:
if (data<4)
putcmd(cp, cmdVolVibratoSetWave, data);
break;
case 0x9:
if (data)
putcmd(cp, cmdRetrig, data);
break;
case 0xA:
putcmd(cp, cmdRowVolSlideUp, data<<2);
break;
case 0xB:
putcmd(cp, cmdRowVolSlideDown, data<<2);
break;
case 0xC:
putcmd(cp, cmdNoteCut, data);
break;
}
break;
case 0x14:
putcmd(cp, cmdKeyOff, 0);
break;
case 0x15:
if (data)
putcmd(cp, cmdSetEnvPos, data);
break;
case 0x19:
if (!data)
putcmd(cp, cmdPanSlide, 0);
else
if (data&0xF0)
putcmd(cp, cmdPanSlide, data>>4);
else
putcmd(cp, cmdPanSlide, -(data&0xF));
break;
case 0x1B:
putcmd(cp, cmdRetrig, data);
break;
case 0x1D:
putcmd(cp, cmdTremor, data);
break;
case 0x21:
if ((data&0xF0)==0x10)
putcmd(cp, cmdRowPitchSlideUp, (data&0xF)<<2);
else
if ((data&0xF0)==0x20)
putcmd(cp, cmdRowPitchSlideDown, (data&0xF)<<2);
break;
case 0x22:
putcmd(cp, cmdPanHeight, (data>>4)*0x11);
putcmd(cp, cmdPanDepth, (data&0xF)*0x11);
break;
}
if (cp!=(tp+2))
{
tp[0]=row;
tp[1]=cp-tp-2;
tp=cp;
}
}
track &trk=m.tracks[t*(m.channum+1)+i];
unsigned short len=tp-temptrack;
if (!len)
trk.ptr=trk.end=0;
else
{
trk.ptr=new unsigned char[len];
trk.end=trk.ptr+len;
if (!trk.ptr)
return errAllocMem;
memcpy(trk.ptr, temptrack, len);
}
}
unsigned char *tp=temptrack;
unsigned char *buf=buffer;
unsigned short row, q;
for (row=0; row<pathead.rows; row++)
{
unsigned char *cp=tp+2;
if (!row&&(t==head2.ord[0]))
{
if (head2.tempo!=6)
putcmd(cp, cmdTempo, head2.tempo);
if (head2.speed!=125)
putcmd(cp, cmdSpeed, head2.speed);
}
for (q=0; q<m.channum; q++)
{
unsigned char x=0x1F;
if (*buf&0x80)
x=*buf++&~0x80;
signed short command=-1;
unsigned char data=0;
if (x&1)
buf++;
if (x&2)
buf++;
if (x&4)
buf++;
if (x&8)
command=*buf++;
if (x&16)
data=*buf++;
switch (command)
{
case 0xB:
putcmd(cp, cmdGoto, data);
break;
case 0xD:
putcmd(cp, cmdBreak, (data&0x0F)+(data>>4)*10);
break;
case 0xE:
switch (data>>4)
{
case 0x6:
putcmd(cp, cmdSetChan, q);
putcmd(cp, cmdPatLoop, data&0xF);
break;
case 0xE:
putcmd(cp, cmdPatDelay, data&0xF);
break;
}
break;
case 0xF:
if (data)
if (data<0x20)
putcmd(cp, cmdTempo, data);
else
putcmd(cp, cmdSpeed, data);
else
putcmd(cp, cmdGoto, 0);
break;
case 0x10:
putcmd(cp, cmdGlobVol, (data>0x3F)?0xFF:(data<<2));
break;
case 0x11:
if ((data&0x0F)&&(data&0xF0))
break;
putcmd(cp, cmdSetChan, q);
if (data&0xF0)
putcmd(cp, cmdGlobVolSlide, (data>>4)<<2);
else
putcmd(cp, cmdGlobVolSlide, -((data&0xF)<<2));
}
}
if (cp!=(tp+2))
{
tp[0]=row;
tp[1]=cp-tp-2;
tp=cp;
}
}
track &trk=m.tracks[t*(m.channum+1)+m.channum];
unsigned short len=tp-temptrack;
if (!len)
trk.ptr=trk.end=0;
else
{
trk.ptr=new unsigned char[len];
trk.end=trk.ptr+len;
if (!trk.ptr)
return errAllocMem;
memcpy(trk.ptr, temptrack, len);
}
}
delete temptrack;
delete buffer;
m.sampnum=0;
m.modsampnum=0;
for (i=0; i<m.instnum; i++)
{
instrument &ip=m.instruments[i];
envelope *env=m.envelopes+2*i;
smps[i]=0;
msmps[i]=0;
struct
{
unsigned long size;
char name[22];
char type;
unsigned short samp;
} ins1;
file.read(&ins1, sizeof(ins1));
memcpy(ip.name, ins1.name, 22);
ip.name[22]=0;
instsmpnum[i]=ins1.samp;
if (!ins1.samp)
{
file.seekcur(ins1.size-sizeof(ins1));
continue;
}
struct
{
unsigned long shsize;
unsigned char snum[96];
unsigned short venv[12][2];
unsigned short penv[12][2];
unsigned char vnum, pnum;
unsigned char vsustain, vloops, vloope, psustain, ploops, ploope;
unsigned char vtype, ptype;
unsigned char vibtype, vibsweep, vibdepth, vibrate;
unsigned short volfade;
unsigned short res;
} ins2;
file.read(&ins2, sizeof(ins2));
file.seekcur(ins1.size-sizeof(ins1)-sizeof(ins2));
smps[i]=new sampleinfo[ins1.samp];
msmps[i]=new sample[ins1.samp];
if (!ip.samples||!smps[i]||!msmps[i])
return errAllocMem;
memset(msmps[i], 0, sizeof(**msmps)*ins1.samp);
memset(smps[i], 0, sizeof(**smps)*ins1.samp);
for (j=0; j<96; j++)
if (ins2.snum[j]<ins1.samp)
ip.samples[j+12]=m.modsampnum+ins2.snum[j];
unsigned short volfade=0xFFFF;
if (ins2.vtype&1)
{
volfade=ins2.volfade;
env[0].speed=0;
env[0].type=0;
env[0].env=new unsigned char[ins2.venv[ins2.vnum-1][0]+1];
if (!env[0].env)
return errAllocMem;
short k, p=0, h=ins2.venv[0][1]*4;
for (j=1; j<ins2.vnum; j++)
{
short l=ins2.venv[j][0]-p;
short dh=ins2.venv[j][1]*4-h;
for (k=0; k<l; k++)
{
short cv=h+dh*k/l;
env[0].env[p++]=(cv>255)?255:cv;
}
h+=dh;
}
env[0].len=p;
env[0].env[p]=(h>255)?255:h;
if (ins2.vtype&2)
{
env[0].type|=mpEnvSLoop;
if (!(ins2.vtype&4)||(ins2.vsustain<=ins2.vloope))
{
env[0].sloops=ins2.venv[ins2.vsustain][0];
env[0].sloope=ins2.venv[ins2.vsustain][0]+1;
}
else
{
env[0].sloops=ins2.venv[ins2.vloops][0];
env[0].sloope=ins2.venv[ins2.vloope][0];
}
}
if (ins2.vtype&4)
{
if ((ins2.vtype&2)&&(ins2.vsustain==ins2.vloope))
{
env[0].type|=mpEnvSLoop;
env[0].sloops=ins2.venv[ins2.vloops][0];
env[0].sloope=ins2.venv[ins2.vloope][0];
}
else
{
env[0].type|=mpEnvLoop;
env[0].loops=ins2.venv[ins2.vloops][0];
env[0].loope=ins2.venv[ins2.vloope][0];
}
}
}
if (ins2.ptype&1)
{
env[1].speed=0;
env[1].type=0;
env[1].env=new unsigned char[ins2.penv[ins2.pnum-1][0]+1];
if (!env[1].env)
return errAllocMem;
short k, p=0, h=ins2.penv[0][1]*4;
for (j=1; j<ins2.pnum; j++)
{
short l=ins2.penv[j][0]-p;
short dh=ins2.penv[j][1]*4-h;
for (k=0; k<l; k++)
{
short cv=h+dh*k/l;
env[1].env[p++]=(cv>255)?255:cv;
}
h+=dh;
}
env[1].len=p;
env[1].env[p]=(h>255)?255:h;
if (ins2.ptype&2)
{
env[1].type|=mpEnvSLoop;
if (!(ins2.ptype&4)||(ins2.psustain<=ins2.ploope))
{
env[1].sloops=ins2.penv[ins2.psustain][0];
env[1].sloope=ins2.penv[ins2.psustain][0]+1;
}
else
{
env[1].sloops=ins2.penv[ins2.ploops][0];
env[1].sloope=ins2.penv[ins2.ploope][0];
}
}
if (ins2.ptype&4)
{
if ((ins2.ptype&2)&&(ins2.psustain==ins2.ploope))
{
env[1].type|=mpEnvSLoop;
env[1].sloops=ins2.penv[ins2.ploops][0];
env[1].sloope=ins2.penv[ins2.ploope][0];
}
else
{
env[1].type|=mpEnvLoop;
env[1].loops=ins2.penv[ins2.ploops][0];
env[1].loope=ins2.penv[ins2.ploope][0];
}
}
}
/*
unsigned char pchsweep;
if (ins2.vibdepth&&ins2.vibrate)
{
env[2].speed=0;
env[2].opt=0;
env[2].len=256;
env[2].sustain=-1;
env[2].loops=0;
env[2].loope=256;
env[2].env=new unsigned char [256];
if (!env[2].env)
return errAllocMem;
unsigned char ph=0;
for (j=0; j<256; j++)
{
ph+=ins2.vibrate;
switch (ins2.vibtype)
{
case 0:
env[2].env[j]=128+((ins2.vibdepth*vibsintab[ph])>>10);
break;
case 1:
env[2].env[j]=128+((ins2.vibdepth*(64-(ph&128)))>>5);
break;
case 2:
env[2].env[j]=128+((ins2.vibdepth*(128-ph))>>6);
break;
case 3:
env[2].env[j]=128+((ins2.vibdepth*(ph-128))>>6);
break;
}
}
}
*/
for (j=0; j<ins1.samp; j++)
{
struct
{
unsigned long samplen;
unsigned long loopstart;
unsigned long looplen;
unsigned char vol;
signed char finetune;
unsigned char type;
unsigned char pan;
signed char relnote;
unsigned char res;
unsigned char name[22];
} samp;
file.read(&samp, sizeof (samp));
file.seekcur(ins2.shsize-sizeof(samp));
if (samp.type&16)
{
samp.samplen>>=1;
samp.loopstart>>=1;
samp.looplen>>=1;
}
sample &sp=msmps[i][j];
memcpy(sp.name, samp.name, 22);
sp.name[22]=0;
sp.handle=0xFFFF;
sp.normnote=-samp.relnote*256-samp.finetune*2;
sp.stdvol=(samp.vol>0x3F)?0xFF:(samp.vol<<2);
sp.stdpan=samp.pan;
sp.opt=0;
sp.volfade=volfade;
sp.vibtype=ins2.vibtype;
sp.vibdepth=ins2.vibdepth<<2;
sp.vibspeed=0;
sp.vibrate=ins2.vibrate<<8;
sp.vibsweep=0xFFFF/(ins2.vibsweep+1);
sp.volenv=env[0].env?(2*i+0):0xFFFF;
sp.panenv=env[1].env?(2*i+1):0xFFFF;
sp.pchenv=0xFFFF;
sampleinfo &sip=smps[i][j];
sip.length=samp.samplen;
sip.loopstart=samp.loopstart;
sip.loopend=samp.loopstart+samp.looplen;
sip.samprate=8363;
sip.type=mcpSampDelta|((samp.type&16)?mcpSamp16Bit:0)|((samp.type&3)?(((samp.type&3)==2)?(mcpSampLoop|mcpSampBiDi):mcpSampLoop):0);
}
for (j=0; j<ins1.samp; j++)
{
sample &sp=msmps[i][j];
sampleinfo &sip=smps[i][j];
unsigned long l=sip.length<<(!!(sip.type&mcpSamp16Bit));
if (!l)
continue;
sip.ptr=new char [l+16];
if (!sip.ptr)
return errAllocMem;
file.read(sip.ptr, l);
sp.handle=m.sampnum+j;
}
m.sampnum+=ins1.samp;
m.modsampnum+=ins1.samp;
}
if (!m.allocsamples()||!m.allocmodsamples())
return errAllocMem;
m.sampnum=0;
m.modsampnum=0;
for (i=0; i<m.instnum; i++)
{
for (j=0; j<instsmpnum[i]; j++)
{
m.samples[m.sampnum++]=smps[i][j];
m.modsamples[m.modsampnum++]=msmps[i][j];
}
delete smps[i];
delete msmps[i];
}
delete smps;
delete msmps;
delete instsmpnum;
return errOk;
}